#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QFileDialog>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>
#include <QSerialPortInfo>
#include <QTime>
#include <iostream>
#include <clickcombobox.h>

#define BTN_COUNT 13

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->serialPort = new QSerialPort(this);
    this->lastStr = "";
    this->timer = new QTimer(this);
    this->CurTimer = new QTimer(this);
    this->LoopTimr = new QTimer(this);
    this->index = 1;




    for(int pos = 0; pos < BTN_COUNT; pos++)
    {
        QString strBtn =  QString("btnSend_%1").arg(pos);
        QPushButton *button = this->findChild<QPushButton *>(strBtn);
        button->setProperty("index",pos);
        if(button)
            btnList.append(button);

        QString strLineEdit =  QString("lineEditSnedText_%1").arg(pos);
        QLineEdit *lineEdit = this->findChild<QLineEdit *>(strLineEdit);
        lineEdit->setProperty("index",pos);
        if(lineEdit)
            LineEditList.append(lineEdit);

        QString strCheck =  QString("checkBoxHex_%1").arg(pos);
        QCheckBox *checkBox = this->findChild<QCheckBox *>(strCheck);
        checkBox->setProperty("index",pos);
        if(checkBox)
            CheckList.append(checkBox);

    }


    // 添加端口号
    this->addSerialPort();

    // 添加波特率
    QList<qint32> serialBaudList = QSerialPortInfo::standardBaudRates();
    for(auto pos : serialBaudList)
    {
        ui->comboBoxBaud->addItem(QString::number(pos));
    }

    // 添加数据位Data5, Data6, Data7, Data8
    QStringList serialDataList = {"Data5","Data6","Data7","Data8"};
    ui->comboBoxDateBit->addItems(serialDataList);

    // 添加校验位 Parity { NoParity, EvenParity, OddParity, SpaceParity, MarkParity, UnknownParity }
    QStringList serialParityList = {"No","Even","Odd","Space","Mark"};
    ui->comboBoxCheckBit->addItems(serialParityList);

    // 添加停止位 StopBits { OneStop, OneAndHalfStop, TwoStop, UnknownStopBits }
    QStringList serialStopList = {"One","OneAndHalf","Two"};
    ui->comboBoxStopBit->addItems(serialStopList);

    // 添加流控 FlowControl { NoFlowControl, HardwareControl, SoftwareControl, UnknownFlowControl }
    QStringList serialFlowList = {"No","Hardware","Software"};
    ui->comboBoxFlowControl->addItems(serialFlowList);


    // 绑定槽函数 按键点击
    for(int pos = 0; pos < BTN_COUNT; pos++)
    {
        QObject::connect(btnList[pos],&QPushButton::clicked,this,&Widget::on_btnSend_clicked);
        QObject::connect(CheckList[pos],&QCheckBox::clicked,this,&Widget::on_checkBoxHex_clicked);
    }


    QObject::connect(this,&Widget::btnSend_clicked,this,&Widget::on_Send_str);

    // 绑定端口接受函数 QSerialPort
    QObject::connect(serialPort,&QSerialPort::readyRead,this,&Widget::on_Rec_str);
    //定时发送
    QObject::connect(timer,&QTimer::timeout,[this](){this->on_Send_str(0);});


    QObject::connect(CurTimer,&QTimer::timeout,[=](){
                        QString timeStr=QDateTime::currentDateTime().toString("yyyy-dd-MM hh:mm:ss");
                        ui->labelCurTime->setText(timeStr);
                                                  });
    CurTimer->start(500);

    // 循环定时器
    QObject::connect(LoopTimr,&QTimer::timeout,this,&Widget::on_LoopTimer_clicked);


    // 绑定监听 串口

    connect(serialPort, &QSerialPort::errorOccurred, this, &Widget::handleSerialError);

    QObject::connect(ui->comboBoxPort,&ClickComboBox::portReset,[=](){
                                                     qDebug() << "comboBoxPort 被左键点击";
                                                     this->addSerialPort();
                                                });

    //设置默认选项

    QString timeStr=QDateTime::currentDateTime().toString("yyyy-dd-MM hh:mm:ss");
    ui->labelCurTime->setText(timeStr);
    ui->labelSendState->setText("Welcome to use");
    ui->checkBoxLoop->setEnabled(false);

    ui->comboBoxBaud->setCurrentIndex(12);
    ui->comboBoxDateBit->setCurrentIndex(3);
    ui->comboBoxCheckBit->setCurrentIndex(0);
    ui->comboBoxStopBit->setCurrentIndex(0);
    ui->comboBoxFlowControl->setCurrentIndex(0);

    ui->checkBoxLine->setChecked(true);

    for(int pos = 0; pos < BTN_COUNT; pos++)
        btnList[pos]->setEnabled(false);
    ui->checkBoxTimerSend->setEnabled(false);

}

Widget::~Widget()
{
    delete ui;
}



void Widget::on_btnOpenOrClose_clicked(bool checked)
{
    if (checked)
    {
        ui->btnOpenOrClose->setText("关闭串口");

        // 设置端口名
        QString portName = ui->comboBoxPort->currentText();
        serialPort->setPortName(portName);

        // 设置波特率
        bool ok;
        int baudRate = ui->comboBoxBaud->currentText().toInt(&ok);
        if (!ok) {
            qDebug() << "波特率转换错误，设置默认115200";
            baudRate = 115200;
        }
        serialPort->setBaudRate(baudRate);

        // 设置数据位
        switch(ui->comboBoxDateBit->currentIndex()) {
        case 0: serialPort->setDataBits(QSerialPort::Data5); break;
        case 1: serialPort->setDataBits(QSerialPort::Data6); break;
        case 2: serialPort->setDataBits(QSerialPort::Data7); break;
        case 3:
        default: serialPort->setDataBits(QSerialPort::Data8); break;
        }

        // 设置校验
        switch(ui->comboBoxCheckBit->currentIndex()) {
        case 0: serialPort->setParity(QSerialPort::NoParity); break;
        case 1: serialPort->setParity(QSerialPort::EvenParity); break;
        case 2: serialPort->setParity(QSerialPort::OddParity); break;
        case 3: serialPort->setParity(QSerialPort::SpaceParity); break;
        case 4: serialPort->setParity(QSerialPort::MarkParity); break;
        }

        // 设置停止位
        switch(ui->comboBoxStopBit->currentIndex()) {
        case 0: serialPort->setStopBits(QSerialPort::OneStop); break;
        case 1: serialPort->setStopBits(QSerialPort::OneAndHalfStop); break;
        case 2: serialPort->setStopBits(QSerialPort::TwoStop); break;
        }

        // 设置流控制
        switch(ui->comboBoxFlowControl->currentIndex()) {
        case 0: serialPort->setFlowControl(QSerialPort::NoFlowControl); break;
        case 1: serialPort->setFlowControl(QSerialPort::HardwareControl); break;
        case 2: serialPort->setFlowControl(QSerialPort::SoftwareControl); break;
        }

        // 打开串口
        if (serialPort->open(QIODevice::ReadWrite))
        {
            qDebug() << "串口打开成功:" << serialPort->portName();
            for(int pos = 0; pos < BTN_COUNT; pos++)
                btnList[pos]->setEnabled(true);
            ui->checkBoxTimerSend->setEnabled(true);
            ui->groupBox_4->setEnabled(false);
            QString strstate =QString("Open %1").arg(serialPort->portName()) ;
            ui->labelSendState->setText(strstate);
            ui->checkBoxLoop->setEnabled(true);
        }
        else
        {
            qDebug() << "串口打开失败:" << serialPort->errorString();
            //操作失败后，可以考虑重置按钮状态
            ui->btnOpenOrClose->setChecked(false);
            ui->btnOpenOrClose->setText("打开串口");
        }

    }
    else
    {
        QString strstate =QString("Close %1").arg(serialPort->portName()) ;
        ui->labelSendState->setText(strstate);

        if (serialPort->isOpen()) {
            serialPort->close();
            qDebug() << "串口已关闭";
        }
        ui->btnOpenOrClose->setText("打开串口");

        if(ui->checkBoxTimerSend->isChecked())
        {
            this->timer->stop();
            ui->checkBoxTimerSend->setChecked(false);
        }



        for(int pos = 0; pos < BTN_COUNT; pos++)
            btnList[pos]->setEnabled(false);
        ui->checkBoxTimerSend->setEnabled(false);
        ui->groupBox_4->setEnabled(true);
        ui->checkBoxLoop->setEnabled(true);
    }
}

void Widget::on_btnSend_clicked()
{
    QPushButton* btn = qobject_cast<QPushButton*>(sender());
    if(btn) {
        QVariant value = btn->property("index");
        if(value.isValid()) {
            emit btnSend_clicked(value.toInt());
        } else {
            qDebug() << "property 'index' invalid.";
        }
    } else {
        qDebug() << "sender() is not QPushButton";
    }
}

void Widget::on_Send_str(int index)
{
    qDebug() << index;
    // 获取文本
    QString strSend = LineEditList[index]->text();

    if(strSend.isEmpty())
    {
        ui->labelSendState->setText("Send Failed !");
        ui->labelSendCount->setText("Sent:0");
        return;
    }

    // 是否添加'\r''\n'
    if(ui->checkBoxNewLine->isChecked())
    {
        qDebug() << "添加换行符号";
        strSend+="\r\n";
    }

    // 发送文本
    if(serialPort->write(strSend.toUtf8()) > 0)
    {
        ui->labelSendState->setText("Send Ok !");
        ui->labelSendCount->setText(QString("Sent:%1").arg(strSend.size()));
    }
    else
    {
        ui->labelSendState->setText("Send Failed !");
        ui->labelSendCount->setText("Sent:0");
    }


}

void Widget::on_Rec_str()
{
    bool flag = false;
    QByteArray data = serialPort->readAll();

    if(data.isEmpty())
        ui->labelSendState->setText("Receive Failed !");
    else
        ui->labelSendState->setText("Receive Ok !");


    QString str = QString::fromUtf8(data); // 根据实际编码调整
    ui->labelRecCount->setText(QString("Recevied:%1").arg(str.size()));
    // 追加历史记录
    if(this->lastStr.compare(str) != 0)
    {
        QString strAppend(str);
        QString timeStr = QTime::currentTime().toString("[hh:mm:ss]");
        if(!strAppend.contains("\r\n"))
            strAppend += "\r\n";
        strAppend = timeStr + "->" + strAppend;
        ui->textEditHistory->append(strAppend);
        this->lastStr = str;
    }

    // 是否自动换行
    if(ui->checkBoxLine->isChecked())
    {

         flag = str.contains("\r\n");
         qDebug() << flag;
         if(flag == false)
             flag = true;
         else
             flag = false;
    }

    // 是否为hex显示
    if(ui->checkHex->isChecked())
    {
        QString strconvers(str);
        str = this->toHexWithPrefix(strconvers);
    }

    if(ui->checkBoxTime->isChecked())
    {
        // 获取时间
        QString timeStr = QTime::currentTime().toString("[hh:mm:ss]");
        // 拼接字符串
        str = timeStr + "->:" + str; // 或者使用 append() 方法
    }

    if(flag)
        str += "\r\n";

    ui->textEditRcv->insertPlainText(str);

    // 设置光标显示末尾
    QTextCursor cursor = ui->textEditRcv->textCursor();
    cursor.movePosition(QTextCursor::End);
    ui->textEditRcv->setTextCursor(cursor);



}

void Widget::on_checkBoxHex_clicked(bool checked)
{
    QVariant index;
    QCheckBox* btn = qobject_cast<QCheckBox*>(sender());

    if(btn)
        index = btn->property("index");
    else
        return;

    QString strconvers= LineEditList[index.toInt()]->text();

    // 字符串转化为16进制
    if(checked&&index.isValid())
    {

        // 调用函数
        QString newconvers = toHexWithPrefix(strconvers);
        LineEditList[index.toInt()]->setText(newconvers);

    }
    else  // 16进制转化为字符串
    {
        // 调用函数
        QString newconvers = fromHexWithPrefix(strconvers);
        LineEditList[index.toInt()]->setText(newconvers);
    }

}

QString Widget::toHexWithPrefix(const QString &strconvers)
{
    QByteArray byteArray = strconvers.toUtf8(); // 或根据需要选择编码
    QString hexStr = byteArray.toHex().toUpper(); // 转成大写
    QString formattedHex;
    for (int i = 0; i < hexStr.length(); i += 2) {
        QString byteHex = hexStr.mid(i, 2);
        if (!formattedHex.isEmpty()) {
            formattedHex += " ";
        }
        formattedHex += "0X" + byteHex;
    }
    return formattedHex;

}

QString Widget::fromHexWithPrefix(const QString &strconvers)
{
    // 第一步：去除"0X"和空格，得到连续的十六进制字符串
    QString cleanHex;
    QStringList parts = strconvers.split(' ', QString::SkipEmptyParts);
    for(const QString& part : parts) {
        QString hexPart = part;
        hexPart.remove("0X", Qt::CaseInsensitive);
        cleanHex += hexPart;
    }
    // 第二步：从十六进制还原字节数组
    QByteArray byteArray = QByteArray::fromHex(cleanHex.toUtf8());

    // 第三步：转成字符串
    QString originalStr = QString::fromUtf8(byteArray);

    return originalStr;
}

void Widget::handleSerialError(QSerialPort::SerialPortError error)
{
    switch(error)
    {
        case QSerialPort::OpenError:

            // 消息盒子
            QMessageBox::warning(this, tr("SerialPort"),
                               tr("This port is already in use.\n"),
                               QMessageBox::Ok);

            break;
        case QSerialPort::ResourceError:
            QMessageBox::warning(this, tr("SerialPort"),
                               tr("This port has been disconnected."),
                               QMessageBox::Ok);
            break;

    case QSerialPort::PermissionError:
            QMessageBox::warning(this, tr("SerialPort"),
                                tr("You do not have the necessary "
                                "permission to open this port."),
                                QMessageBox::Ok);
        break;
        default:
            qDebug() << error;
            break;
    }
}

void Widget::addSerialPort()
{
    ui->comboBoxPort->clear();
    // 添加端口号
    QList<QSerialPortInfo> serialPortList =  QSerialPortInfo::availablePorts();
    for(auto pos : serialPortList)
    {
//        qDebug() << pos.portName();
//        qDebug() << pos.description();
        ui->comboBoxPort->addItem(pos.portName());
    }
}

void Widget::on_checkBoxTimerSend_clicked(bool checked)
{
    // 开启定时器
    if(checked)
    {
        qDebug() << "开启定时器";
        this->timer->start(ui->lineEditTime->text().toUInt());
        ui->lineEditTime->setEnabled(false);
    }
    else
    {
        qDebug() << "关闭定时器";
        ui->lineEditTime->setEnabled(true);
        this->timer->stop();

    }

}

void Widget::on_btnClearRec_clicked()
{
    // 清空接受缓冲区
    ui->textEditRcv->clear();


}

void Widget::on_btnSavaRcv_clicked()
{
    // 保存接受的信息
    qDebug() << "on_btnSavaRcv_clicked";
    QString saveText;
    saveText = ui->textEditRcv->toPlainText();

    if(saveText.isEmpty())
        return;

    QString savefilename = QString("D:/tmptest/%1.txt").arg(QTime::currentTime().toString("hhmmss"));

    // 打开文件对话框
    QString fileName = QFileDialog::getSaveFileName(this,
                                     tr("Save File"),
                                    savefilename,
                                    tr("Text Files (*.txt)"));
    if(!fileName.isNull())
    {
        QFile file;
        QTextStream textStream;
        file.setFileName(fileName);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
            goto end;

        textStream.setDevice(&file);
        // 写入文件
        textStream << saveText;
        textStream.flush();

        file.close();

    }

end:
    return;

}

void Widget::on_btnHidePanel_clicked(bool checked)
{
    if(checked)
    {
        // 隐藏面板
        ui->btnHidePanel->setText("拓展面板");
        ui->groupBox_3->hide();

    }
    else
    {
        ui->btnHidePanel->setText("隐藏面板");
        ui->groupBox_3->show();
    }
}

void Widget::on_btnHideHistory_clicked(bool checked)
{
    if(checked)
    {
        // 隐藏面板
        ui->btnHideHistory->setText("拓展历史");
        ui->groupBox_2->hide();

    }
    else
    {
        ui->btnHideHistory->setText("隐藏历史");
        ui->groupBox_2->show();
    }
}

void Widget::on_checkBoxLoop_clicked(bool checked)
{
    if(checked)
    {
        // 开启循环发送
        // 开启定时器
        this->LoopTimr->start(ui->spinBoxLoopTime->text().toUInt());
        ui->spinBoxLoopTime->setEnabled(false);
    }
    else
    {
        // 关闭循环发送
        // 关闭定时器
        ui->spinBoxLoopTime->setEnabled(true);
        this->LoopTimr->stop();
    }
}

void Widget::on_LoopTimer_clicked()
{

    qDebug() << "index:" << index;

    this->on_Send_str(this->index);
    // 限定在 1~12
    index = (index % (BTN_COUNT-1))+1;


}

void Widget::on_btnSaveText_clicked()
{
    /*保存为 json 格式 的文件
     *  {
     *      "index1":{ "Hex": bool,"lineEditSnedText": string},
     *      "index2":{ "Hex": bool,"lineEditSnedText": string}
     *      ....
     *  }
    */

    QJsonObject root;
    QJsonObject index;
    QString keyIndex;

    // 拼接 json 数据帧

    for(int pos = 1 ; pos < BTN_COUNT ; pos++)
    {
        index.insert("Hex",CheckList[pos]->isChecked());
        index.insert("lineEditSnedText",LineEditList[pos]->text());
        keyIndex = QString("index%1").arg(pos);
        root.insert(keyIndex,index);
    }

    // 转化为 josn字符串
    QJsonDocument doc;
    doc.setObject(root);



    // 打开文件对话框

    QString savefilename = QString("D:/tmptest/%1").arg(QTime::currentTime().toString("hhmmss"));

    // 打开文件对话框
    QString fileName = QFileDialog::getSaveFileName(this,
                                     tr("Save File"),
                                    savefilename,
                                    tr("Text Files (*.json)"));
    if(!fileName.isNull())
    {
        QFile file;
        QTextStream textStream;
        file.setFileName(fileName);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
            goto end;
        textStream.setDevice(&file);
        // 写入文件
        textStream << doc.toJson();
        textStream.flush();
        file.close();
    }

end:
    return;


}

void Widget::on_btnLoadText_clicked()
{
    // 解析为 json 格式 的文件 并加载到 lineedit

    // 打开文件对话框
    QString loadfilpath = QString("D:/tmptest/");
    QString fileName = QFileDialog::getOpenFileName(this,
                                            tr("Load Json"),
                                            loadfilpath,
                                            tr("Text Files (*.json *.txt )"));

    if(!fileName.isNull())
    {

        // 打开文件
        QFile file(fileName);
        if (!file.open(QFile::ReadOnly | QFile::Text)) {
            qDebug() << "can't open error!";
            goto end;
        }

        // 读取文件的全部内容
        QTextStream stream(&file);
        stream.setCodec("UTF-8");		// 设置读取编码是UTF8
        QString str = stream.readAll();
        file.close();

        QJsonDocument JsonDoc;
        // QJsonParseError类用于在JSON解析期间报告错误。
        QJsonParseError jsonError;

        // 加载 josn字符串
        JsonDoc = QJsonDocument::fromJson(str.toUtf8(), &jsonError);

        if(JsonDoc.isEmpty())
        {
            qDebug() << "加载josn错误";
            goto  end;
        }

        QJsonObject rootJson = JsonDoc.object();

        qDebug() << rootJson;

        QJsonValue Hex;
        QJsonValue lineEditSnedText;
        QJsonValue valueJson;
        QString keyIndex;
        QJsonObject Index;


        for(int pos = 1 ; pos < BTN_COUNT; pos++)
        {
            keyIndex = QString("index%1").arg(pos);

            valueJson = rootJson.value(keyIndex);
            if(valueJson.type() != QJsonValue::Object)
                goto format;
            Index = valueJson.toObject();

            Hex = Index.value("Hex");
            if(Hex.type() != QJsonValue::Bool)
                goto format;

            lineEditSnedText = Index.value("lineEditSnedText");
            if(lineEditSnedText.type() != QJsonValue::String)
                goto format;

            // 加载到 多行文本框中
            CheckList[pos]->setChecked(Hex.toBool());
            LineEditList[pos]->setText(lineEditSnedText.toString());
        }

    }

format:
    qDebug() << "Json 格式错误";
end:
    return;

}

void Widget::on_btnResetText_clicked()
{
    // 清除 lineedit的内容
    for(int pos = 1 ; pos < BTN_COUNT; pos++)
    {
        CheckList[pos]->setChecked(false);
        LineEditList[pos]->setText("");
    }
}
